﻿using System;
using System.Xml.Linq;
using Microsoft.Office.OneNote.Interop;

namespace Microsoft.Office.OneNote
{
    public abstract class OneNoteHierarchyObject : OneNoteObjectWithIdentity, IOneNoteHierarchy
    {
        private static readonly OneNoteProperty IsCurrentlyViewedProperty =
            OneNoteProperty.Register("isCurrentlyViewed", typeof(Boolean), typeof(OneNoteHierarchyObject));

        private OneNoteHierarchyObject _parent;
        private OneNoteHierarchy _hierarchy;

        internal OneNoteHierarchyObject(OneNoteObjectId id)
            : base(id)
        {
        }

        public Uri Url
        {
            get
            {
                CheckValid();
                return OneNoteApplication.Current.GetHyperlinkToObject(ObjectId, OneNoteObjectId.Empty);
            }
        }

        public OneNoteHierarchyObject Parent
        {
            get
            {
                CheckValid();
                return _parent;
            }
            internal set
            {
                CheckValid();

                if (_parent != value)
                {
                    _parent = value;
                    OnParentChanged();
                }
            }
        }

        public Boolean IsCurrentlyViewed
        {
            get { return GetValue<Boolean>(IsCurrentlyViewedProperty); }
        }

        internal OneNoteObjectId ParentObjectId
        {
            get
            {
                CheckValid();

                if (Parent != null)
                {
                    return Parent.ObjectId;
                }

                return OneNoteObjectId.Empty;
            }
        }

        internal OneNoteHierarchy Hierarchy
        {
            get
            {
                CheckValid();
                return _hierarchy;
            }
            set
            {
                CheckValid();

                if (_hierarchy != value)
                {
                    if (_hierarchy != null)
                    {
                        throw FrameworkExceptions.CannotChangeHierarchy();
                    }

                    _hierarchy = value;
                    OnHierarchyChanged();
                }
            }
        }

        internal virtual void OnHierarchyChanged()
        {
        }

        internal virtual void OnParentChanged()
        {
        }

        // Submitting

        public void SubmitChanges()
        {
            CheckValid();

            XDocument changes = OneNoteSchema.CreateDocument();
            WriteTo(changes);

            DoSubmitChanges(changes);
        }

        internal virtual void DoSubmitChanges(XDocument changes)
        {
            OneNoteApplication.Current.UpdateHierarchy(changes);
        }

        // Invalidating

        internal override void MarkInvalidOverride()
        {
            base.MarkInvalidOverride();

            _parent = null;
            _hierarchy = null;
        }

        // Updating

        public void Update()
        {
            CheckValid();

            if (Hierarchy == null)
            {
                throw new InvalidOperationException();
            }

            XDocument document = GetHierarchy(UpdateScope);
            OneNoteSchema.Deserialize(this, document.Root);
        }

        internal XDocument GetHierarchy(HierarchyScope scope)
        {
            return OneNoteApplication.Current.GetHierarchy(ObjectId, scope);
        }

        internal virtual HierarchyScope UpdateScope
        {
            get { return HierarchyScope.Self; }
        }

        // IOneNoteHierarchy

        void IOneNoteHierarchy.MarkChildrenDirty()
        {
            SetFlags(true, OneNoteObjectFlags.ChildrenDirty);
        }

        OneNoteHierarchy IOneNoteHierarchy.Hierarchy
        {
            get { return Hierarchy; }
        }
    }
}
